package com.company;

import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.TreeVisitor;

import java.util.Iterator;



public class LinkedBinaryTree<T> implements BinaryTree{
    public BTNode<T> root;
    public LinkedBinaryTree()
    {
        root = null;
    }
    public LinkedBinaryTree (T element)
    {
        root = new BTNode<T>(element);
    }
    public LinkedBinaryTree (T element, LinkedBinaryTree<T> left,
                             LinkedBinaryTree<T> right)
    {
        root = new BTNode<T>(element);
        root.setLeft(left.root);
        root.setRight(right.root);
    }
    public T getRootElement() throws Exception {
        if (root == null)
            throw new Exception ("Get root operation "
                    + "failed. The tree is empty.");

        return root.getElement();
    }
    public LinkedBinaryTree<T> getLeft() throws Exception {
        if (root == null)
            throw new Exception ("Get left operation "
                    + "failed. The tree is empty.");

        LinkedBinaryTree<T> result = new LinkedBinaryTree<T>();
        result.root = root.getLeft();

        return result;
    }
    public T find (T target) throws Exception {
        BTNode<T> node = null;

        if (root != null)
            node = root.find(target);

        if (node == null)
            throw new Exception("Find operation failed. "
                    + "No such element in tree.");

        return node.getElement();
    }
    public int size()
    {
        int result = 0;

        if (root != null)
            result = root.count();

        return result;
    }
    public Iterator<T> inorder()
    {
        ArrayIterator<T> iter = new ArrayIterator<T>();

        if (root != null)
            root.inorder (iter);

        return  iter;
    }
    public Iterator<T> levelorder() throws Exception {
        LinkedQueue<BTNode<T>> queue = new LinkedQueue<BTNode<T>>();
        ArrayIterator<T> iter = new  ArrayIterator<T>();

        if (root != null)
        {
            queue.enqueue(root);
            while (!queue.isEmpty())
            {
                BTNode<T> current = queue.dequeue();

                iter.add (current.getElement());

                if (current.getLeft() != null)
                    queue.enqueue(current.getLeft());
                if (current.getRight() != null)
                    queue.enqueue(current.getRight());
            }
        }

        return iter;
    }
    public Iterator<T> ArrayIterator()
    {
        return inorder();
    }
    public LinkedBinaryTree<T> getRight() throws Exception {
        if (root == null)
            throw new Exception ("Get Right operation "
                    + "failed. The tree is empty.");
        LinkedBinaryTree<T> result = new LinkedBinaryTree<T>();
        result.root = root.getRight();

        return result;
    }
    public boolean contains (T target) throws Exception {
        BTNode<T> node = null;
        boolean result = true;
        if (root != null)
            node = root.find(target);
        if(node == null)
            result = false;
        return result;
    }
    public boolean isEmpty() {
        return (root.count()==0);
    }
    public String toString() {
        ArrayIterator<T> list = (ArrayIterator<T>) preorder();
        String result = "<top of Tree>\n";
        for(T i : list){
            result += i + "\t";
        }
        return result + "<bottom of Tree>";
    }
    public  Iterator<T> preorder() {
        ArrayIterator<T> list = new  ArrayIterator<>();

        if(root!=null)
            root.preorder(list);
        return list;
    }

    public  Iterator<T> postorder() {
        ArrayIterator<T> list = new  ArrayIterator<>();

        if(root!=null)
            root.postorder(list);
        return list;
    }



    @Override
    public ExpressionTree getLeftOperand() {
        return null;
    }

    @Override
    public ExpressionTree getRightOperand() {
        return null;
    }

    @Override
    public Kind getKind() {
        return null;
    }

    @Override
    public <R, D> R accept(TreeVisitor<R, D> treeVisitor, D d) {
        return null;
    }
}
